#include <SFML/Graphics/RenderWindow.hpp>
#include <nice2d/macros.h>
#include <nice2d/scene.h>
#include <nice2d/background.h>
#include <nice2d/imagedescriptor.h>
#include <nice2d/util.h>
#include <nice2d/tilemap.h>
#include <nice2d/input.h>
#include <nice2d/widgets/label.h>
#include <nice2d/widgets/boxlayout.h>
#include <nice2d/widgets/desktop.h>
#include <nice2d/components/group.h>
#include <nice2d/components/spritestatus.h>
#include <nice2d/components/imagemanager.h>
#include <nice2d/components/attributetable.h>
#include <nice2d/piece/movepointsearcher.h>
#include <nice2d/piece/piecescene.h>
#include <nice2d/piece/factionmanager.h>
#include <nice2d/piece/piecerandomsorter.h>

#define SCENE_WIDTH  900.0f
#define SCENE_HEIGHT 680.0f

class UnitScene : public PieceScene,public Input
{
public:
    void onInitialed()override
    {
        setInputMessageTarget(shared_from_this());

        setSceneBox({0.0f, 0.0f, SCENE_WIDTH, SCENE_HEIGHT});
        setBackground(Background::create("./../data/images/ground3.png", true));

        initFaction();
        initTileMap();

        searcher = ADD_COMPONENT(Application::getInstance(),MovePointSearcher);
        searcher->setOwner(tileMap);

        attributeTable = ADD_COMPONENT(Application::getInstance(),AttributeTable2D);
        attributeTable->add(0,1,4);

        auto attributeTable3d = ADD_COMPONENT(Application::getInstance(),AttributeTable3D);
        attributeTable3d->add(0,0,AttributeTable_Move,1);

        deployPieces();
        initControls();
    }
private:
    void initFaction()
    {
        auto factionManager = GET_APPLICATION_COMPONENT(FactionManager);
        factionManager->createFaction(sf::Color::Red,L"red");
        factionManager->createFaction(sf::Color::Green,L"green");

        pieceSorter = ADD_COMPONENT(Application::getInstance(),PieceRandomSorter);
    }

    void initTileMap()
    {
        tileMap = TileMap::create(TileMapType::TileMapType_Hex);
        tileMap->init(13,9,96);

        tileMap->accept([](int32_t x, int32_t y, std::shared_ptr<Tile> tile)
        {
            tile->setOutlineColor(sf::Color(128,128,128));
            tile->setOutlineThickness(0.5f);
            tile->setWalkable(true);
        });

        addChild(tileMap);
        setTileMap(tileMap);
        tileMap->tileClicked.connect(std::bind(&UnitScene::tileClicked,this,std::placeholders::_1,std::placeholders::_2));
    }

    void deployPieces()
    {
        TextOption opt;
        opt.characterSize = 15;

        sf::Color spriteColor[] = {sf::Color::Red,sf::Color::Green};

        for(int i=0;i<12;i++)
        {
            auto piece = std::make_shared<Piece>(opt);
            piece->setName(std::wstring(L"Piece") + std::to_wstring(i+1));
            piece->setHitPoint(rand()%5+1);
            piece->setAttack(rand()%5+1);
            piece->setDefense(rand()%5+1);
            piece->setMovement(rand()%5+1);
            piece->setBackgroundColor(sf::Color(140,140,140));
            piece->setSpriteColor(spriteColor[i%2]);
            piece->setSize(64,64);
            piece->addPieceIcon("./../data/icon/nato/units/infantry.png");
            piece->addPieceIcon("./../data/icon/nato/sizes/group.png");
            piece->setTextColor(sf::Color::White);
            addPiece(piece,rand()%13,rand()%9);

            piece->selected.connect(std::bind(&UnitScene::spriteSelected,this,std::placeholders::_1));
        }
    }

    void tileClicked(int32_t x,int32_t y)
    {
        auto tile = tileMap->getTileByIndex(x,y);
        auto sprite = tile->getSprite();
        if(sprite)
        {
            tileMap->accept([](int32_t x, int32_t y, std::shared_ptr<Tile> tile)
            {
                tile->setFillColor(sf::Color::Transparent);
             });

            sprite->select();

            auto tileColor = sprite->getSpriteColor();
            tileColor.a = 36;

            auto list = searcher->search(tileMap,{x,y},sprite->getSpriteColor(),0);
            auto itr = list.begin();
            while(itr != list.end())
            {
                auto tile = tileMap->getTileByIndex(itr->x,itr->y);
                tile->setFillColor(tileColor);
                itr ++;
            }
        }
    }

    void spriteSelected(SpritePointer sprite)
    {
        auto visitor = std::make_shared<PieceVisitor>();
        acceptPieces(visitor);

        sprite->setBackgroundColor(sf::Color(180,180,180));

        auto pieces = visitor->getPieces();
        std::for_each(pieces.begin(),pieces.end(),[&](std::shared_ptr<Piece> piece)
        {
            if(std::dynamic_pointer_cast<Piece>(sprite) != piece)
            {
                piece->unselect();
                piece->setBackgroundColor(sf::Color(140,140,140));
            }
        });
    }

    void initControls()
    {
        auto desktop = GET_APPLICATION_COMPONENT(Desktop);

        auto bar = std::make_shared<VBoxLayout>();
        bar->setLayoutResizeRule(LayoutResizeRule_ResizeLayout);

        auto style = std::make_shared<LayoutStyle>();
        style->normalBackground = Background::create(sf::Color::Transparent);
        style->hoverBackground = style->normalBackground;
        bar->setControlStyle(style);

        currentFactionLabel = std::make_shared<Label>();
        currentPieceLabel = std::make_shared<Label>();

        currentFactionLabel->setSize(150,24);
        currentFactionLabel->setAligment(HMode_Left);
        currentPieceLabel->setSize(150,24);
        currentPieceLabel->setAligment(HMode_Left);

        bar->addWidget(currentFactionLabel);
        bar->addWidget(currentPieceLabel);

        auto dock = desktop->addWidget(bar);
        dock->setDock(true);
        dock->setHorizontalMode(HMode_Left);
        dock->setVertical(VMode_Top);
        dock->setXOffset(6.0f);
        dock->setYOffset(3.0f);

        auto toast = std::make_shared<Label>();
        toast->setSize(290,24);
        toast->setBackgroundColor(sf::Color::Black);
        toast->setText("click space key for switch fanction/piece");
        toast->setPosition(600,3);
        desktop->addWidget(toast);

        auto factionManager = GET_APPLICATION_COMPONENT(FactionManager);
        auto faction = factionManager->getCurrentFaction();
        currentFactionLabel->setText(std::wstring(L"current faction:") + faction->getName());

        pieceSorter->sort(as<PieceScene>(),faction->getColor());

        currentPiece = pieceSorter->pick();
        currentPieceLabel->setText(std::wstring(L"current piece:") + currentPiece->getName());

        currentPiece->setBackgroundColor(sf::Color(180,180,180));
    }

    void onKeyPressed(const sf::Event::KeyEvent &event) override
    {
        if(event.code != sf::Keyboard::Space)
            return;

        auto factionManager = GET_APPLICATION_COMPONENT(FactionManager);
        currentPiece = pieceSorter->pick();

        auto faction = factionManager->getCurrentFaction();
        if(!currentPiece)
        {
            factionManager->switchFaction();
            faction = factionManager->getCurrentFaction();
            currentFactionLabel->setText(std::wstring(L"current faction:") + faction->getName());

            pieceSorter->clear();
            pieceSorter->sort(as<PieceScene>(),faction->getColor());

            currentPiece = pieceSorter->pick();
        }

        currentPieceLabel->setText(std::wstring(L"current piece:") + currentPiece->getName());

        currentPiece->setBackgroundColor(sf::Color(180,180,180));
        spriteSelected(currentPiece);

        auto tile = currentPiece->getConfiguratedTile();
        if(!tile.expired())
        {
            auto index = tile.lock()->getTileIndex();
            tileClicked(index.x,index.y);
        }
    }
private:
    std::shared_ptr<TileMap> tileMap;
    std::shared_ptr<AttributeTable2D> attributeTable;
    std::shared_ptr<MovePointSearcher> searcher;

    std::shared_ptr<Label> currentFactionLabel;
    std::shared_ptr<Label> currentPieceLabel;

    std::shared_ptr<PieceSorter> pieceSorter;
    std::shared_ptr<Piece> currentPiece;
};

DECLARE_MAIN_FUNCTION_WITH_SCENE(SCENE_WIDTH, SCENE_HEIGHT, "unit18", UnitScene)
